package com.meshnetics.gb.stack.mac.primitives;

import com.meshnetics.gb.stack.core.IBParameter;
import com.meshnetics.gb.stack.core.event.StackEventType;
import com.meshnetics.gb.stack.core.event.StackRequest;
import com.meshnetics.gb.stack.mac.RadioMACStackLayer;
import com.meshnetics.gb.type.DataValue;
import com.meshnetics.gb.type.impl.zcl.*;

import java.nio.ByteBuffer;

/**
 * WRITE DESCRIPTION HERE
 *
 * @author AKovylin
 */
public class MACSetRequest extends StackRequest implements MACCommand, MACReplyAwaited {
    public static final byte CODE = 0x5b;

    private final UInt pibAttribute;
    private final Object pibAttributeValue;

    public MACSetRequest(int pibAttribute, Object pibAttributeValue) {
        this((byte) (pibAttribute & 0xff), pibAttributeValue);
    }

    public MACSetRequest(byte pibAttribute, Object pibAttributeValue) {
        this(new Byte(pibAttribute), pibAttributeValue);
    }

    public MACSetRequest(Byte pibAttribute, Object pibAttributeValue) {
        super("macSetRequest", StackEventType.LME_TYPE);
        this.pibAttribute = (UInt) TypeUInt.UINT_8.fromObject(pibAttribute);
        if (pibAttributeValue == null) {
            throw new NullPointerException("pibAttributeValue is null");
        }
        this.pibAttributeValue = pibAttributeValue;
    }

    public MACSetRequest(UInt pibAttribute, DataValue pibAttributeValue) {
        super("macSetRequest", StackEventType.LME_TYPE);
        if (pibAttribute == null) {
            throw new NullPointerException("pibAttribute is null");
        }
        if (pibAttributeValue == null) {
            throw new NullPointerException("pibAttributeValue is null");
        } else if (pibAttributeValue instanceof Bool && ((Bool) pibAttributeValue).isInvalid()) {
            throw new IllegalArgumentException("invalid pibAttributeValue");
        }
        this.pibAttribute = pibAttribute.convert(TypeUInt.UINT_8);
        this.pibAttributeValue = pibAttributeValue;
    }

    public Byte getPibAttribute() {
        return (Byte) pibAttribute.toObject();
    }

    public UInt getPibAttributeType() {
        return pibAttribute;
    }

    /**
     * Returns value of attribute or null is value was set in form of Java object.
     *
     * @return value of attribute or null is value was set in form of Java object
     */
    public DataValue getPibAttributeValueType() {
        return pibAttributeValue instanceof DataValue ? (DataValue) pibAttributeValue : null;
    }

    /**
     * Returns value of attribute in form of Java object.
     *
     * @return value of attribute in form of Java object
     */
    public Object getPibAttributeValue() {
        return pibAttributeValue instanceof DataValue ? ((DataValue) pibAttributeValue).toObject() : pibAttributeValue;
    }

    public byte getCode() {
        return CODE;
    }

    public int getSize(RadioMACStackLayer layer) {
        DataValue value = convertToDataValue(layer, pibAttributeValue);
        return 1 + (value instanceof Str ?
                (value.getDataSize() - ((TypeStr) value.getType()).getLengthFieldSize()) :
                value.getDataSize());
    }

    private DataValue convertToDataValue(RadioMACStackLayer layer, Object value) {
        if (value instanceof DataValue) {
            return (DataValue) value;
        }
        IBParameter ibp = layer.getInformationBase().getParameter(((Number) pibAttribute.toObject()).intValue());
        if (ibp == null) {
            throw new IllegalArgumentException("unknown parameter " + pibAttribute);
        }
        return ibp.getType().fromObject(value);
    }

    public void serialize(ByteBuffer bb, RadioMACStackLayer layer) {
        DataValue value = convertToDataValue(layer, pibAttributeValue);
        IBParameter ibp = layer.getInformationBase().getParameter(((Number) pibAttribute.toObject()).intValue());
        if (ibp == null) {
            throw new IllegalArgumentException("unknown parameter " + pibAttribute);
        }
        if (!value.getType().equals(ibp.getType())) {
            throw new IllegalArgumentException("type mismatch");
        }
        pibAttribute.serialize(bb);
        if (value instanceof Str) {
            ((Str) value).serializeWithoutLength(bb, false);
        } else {
            value.serialize(bb);
        }
    }

    public String toString() {
        return getName() + '(' + pibAttribute + ',' + pibAttributeValue + ')';
    }
}
